package com.inspur.edp.bef.bemanager.validate;

import com.inspur.edp.bcc.biztag.api.BizTagService;
import com.inspur.edp.bcc.biztag.entity.BizTag;
import com.inspur.edp.bef.bemanager.generatedbo.GenerateFromDbo;
import com.inspur.edp.bef.bemanager.service.BeManagerService;
import com.inspur.edp.bef.bemanager.util.CheckInfoUtil;
import com.inspur.edp.bef.bemanager.util.ExpressionVariableCheckUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.LogicDeleteControlInfo;
import com.inspur.edp.bef.bizentity.beenum.BETriggerTimePointType;
import com.inspur.edp.bef.bizentity.beenum.RequestNodeTriggerType;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.bef.bizentity.operation.BizActionBase;
import com.inspur.edp.bef.bizentity.operation.BizCommonDetermination;
import com.inspur.edp.bef.bizentity.operation.BizCommonValdation;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.bizentity.operation.Determination;
import com.inspur.edp.bef.bizentity.operation.Validation;
import com.inspur.edp.bef.bizentity.operation.collection.TccSettingCollection;
import com.inspur.edp.bef.bizentity.operation.componentbase.BizReturnValue;
import com.inspur.edp.bef.bizentity.operation.componentenum.BizParameterType;
import com.inspur.edp.bef.bizentity.operation.componentinterface.IBizParameter;
import com.inspur.edp.bef.bizentity.operation.internalbeaction.IInternalBEAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.IInternalMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.TccSettingElement;
import com.inspur.edp.bef.component.ICompParameter;
import com.inspur.edp.bef.component.ICompParameterCollection;
import com.inspur.edp.bef.component.base.GspComponent;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.collection.CommonValCollection;
import com.inspur.edp.cef.designtime.api.collection.DtmElementCollection;
import com.inspur.edp.cef.designtime.api.collection.ValElementCollection;
import com.inspur.edp.cef.designtime.api.element.ElementDefaultVauleType;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspAssociationKey;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.element.GspEnumValue;
import com.inspur.edp.cef.designtime.api.operation.CommonOperation;
import com.inspur.edp.cef.designtime.api.operation.CommonValidation;
import com.inspur.edp.cef.designtime.api.validate.common.CheckUtil;
import com.inspur.edp.cef.designtime.api.variable.CommonVariableCollection;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.IObjectCollection;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.entity.GspCommonObject;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.databaseobject.api.context.DatabaseReservedWords;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectColumn;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.util.StringUtils;

public class BizEntityValidater {
    private static final String BE_VALIDATOR_EXCEPTION = "BizEntityValidator";

    private static final String MODEL = "业务实体 '{%1$s}' ";
    private static final String OBJECT = "业务实体 '{%1$s}' 中节点 '{%2$s}' ";
    private static final String FIELD = "业务实体 '{%1$s}' 中节点 '{%2$s}' 的字段 '{%3$s}' ";
    private static final String VARIABLE = "业务实体 '{%1$s}' 中'变量集合' 的字段 '{%3$s}' ";
    private static final String VARIABLE_DTM = "业务实体 '{%1$s}' 中'变量集合' 的事件";
    private static final String OPT_BIZACTION = "业务实体 '{%1$s}' 中节点 '{%2$s}' 的内部方法";
    private static final String OPT_MGRACTION = "业务实体 '{%1$s}' 中的对外接口方法";
    private static final String OPT_DETERMINATION = "业务实体 '{%1$s}' 中节点 '{%2$s}' 的事件 ";
    private static final String OPT_VALIDATION = "业务实体 '{%1$s}' 中节点 '{%2$s}' 的校验规则 ";
    private static final String EXPRESSION = "业务实体 '{%1$s}' 中节点 '{%2$s}' 的字段 '{%3$s}' ";
    private static final String ASSOCIATION_ENUM = "字段'{%1$s}'的关联带出字段'{%2$s}'的编号和当前节点上字段'{%3$s}'编号相同，请修改当前节点上字段'{%4$s}'的字段编号";
    private static final String TCCSETTINGS = "业务实体 '{%1$s}' 中节点 '{%2$s}'";
    private static List<String> farriasKeyWrods = new ArrayList<>();

    static {
        farriasKeyWrods.add("properties");
    }
    RefCommonService service;

    private RefCommonService getMetadataService() {
        if (service == null) {
            service = SpringBeanUtils.getBean(RefCommonService.class);
        }
        return service;
    }

    private String metaPath;

    /**
     * 业务实体保存前校验
     *
     * @param model 业务实体
     * @param path  当前路径
     */
    public final void validate(GspBusinessEntity model, String path) {
        metaPath = path;
        String validateResult = validateModel(model, path);
        if (validateResult.length() > 0) {
            //保存前校验不通过，抛异常
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_TEMPLATE_ERROR, validateResult);
        }
    }

    /**
     * 业务实体保存前校验
     *
     * @param model
     * @return 返回报错内容
     */
    private String validateModel(GspBusinessEntity model, String path) {
        ///#region Model
        // 模型基本信息
        String message = validateModelBasicInfo(model, path);
        if (message.length() > 0) {
            return message;
        }
        ///#endregion Model

        ///#region Variables
        message = validateVarableEntity(model);
        if (message.length() > 0) {
            return message;
        }

        ///#endregion


        ///#region Object

        // 所有对象基本信息
        message = validateObjectBasicInfo(model, path); //1. 编号不能重复
        if (message.length() > 0) {
            return message;
        }

        message = validateBizTags(model);
        if (message.length() > 0) {
            return message;
        }

        // 检查主对象ID字段
        message = validateIDElement(model);
        if (message.length() > 0) {
            return message;
        }

//        // 检查主对象的分级信息
//        message = validateObjectHiberarchyInfo(model);
//        if (message.length() > 0)
//        {
//            return message;
//        }

        // 检查所有子对象的关联关系
        message = validateChildRelation(model);
        if (message.length() > 0) {
            return message;
        }

        // 检查所有子对象的关联关系
        message = validateLogicDeleteElement(model);
        if (message.length() > 0) {
            return message;
        }


        ///#endregion Object


        ///#region Field

        // 检查元素的基本信息
        message = validateElementBasicInfo(model);
        if (message.length() > 0) {
            return message;
        }

        if (model.getIsVirtual() == false) {
            //检查元素的数据类型是否和数据对象的数据类型对应
            message = this.validateElementDataType(model);
            if (message.length() > 0) {
                return message;
            }
        }

        //检查元素的默认值
        message = this.validateElementDefaultValue(model);
        if (message.length() > 0) {
            return message;
        }

        // 同一对象上的元素的LabelID不允许重复
        message = validateElementLabelID(model);
        if (message.length() > 0) {
            return message;
        }

        // 同一对象上元素的Name不允许重复
        message = validateElementName(model);
        if (message.length() > 0) {
            return message;
        }



        // 同一对象上的元素的Code不允许重复
        message = validateElementCode(model);
        if (message.length() > 0) {
            return message;
        }

        //字段引用[业务字段]，但是没有配置
        message = validateElementUdt(model);
        if (message.length() > 0) {
            return message;
        }


        ///#endregion Field


        ///#region Operation

        //MgrAction
        message = validateMgrActions(model);
        if (message.length() > 0) {
            return message;
        }

        //obj操作（beAction,validation,determinations）
        message = validateBeActions(model);
        if (message.length() > 0) {
            return message;
        }

        message = validateDeterminations(model);
        if (message.length() > 0) {
            return message;
        }

        message = validateValidations(model);
        if (message.length() > 0) {
            return message;
        }



        message = validateTccSettingCollection(model);
        if (message.length() > 0) {
            return message;
        }

        if (!SpringBeanUtils.getBean(MetadataProjectService.class).isInterpretation(path)) {
            // 关联字段校验。只做生成型
            // 430628 已去掉该校验
           // message = validateAssociateEnum(model);
            if (message.length() > 0) {
                return message;
            }
        }
        ///#endregion Operation

        return "";
    }

    private String validateElementName(GspBusinessEntity model) {
        java.util.ArrayList<IGspCommonElement> allElementList = model.getAllElementList(true);

        if (allElementList != null && allElementList.size() > 0) {
            for (int i = 0; i < allElementList.size() - 1; i++) {
                IGspCommonElement firstElement = allElementList.get(i);
                if (firstElement.getIsRefElement()) {
                    continue;
                }
                for (int j = i + 1; j < allElementList.size(); j++) {
                    IGspCommonElement secondElement = allElementList.get(j);
                    if (secondElement.getIsRefElement()) {
                        continue;
                    }
                    if (firstElement.getName().equals(secondElement.getName()) && firstElement.getBelongObject().getID().equals(secondElement.getBelongObject().getID())) {
                        String message = String.format("业务实体 '%1$s' 的节点 '%2$s' 中字段 '%3$s' 和字段 '%4$s' 的 [名称] 属性不允许重复! ", model.getName(), firstElement.getBelongObject().getName(), firstElement.getLabelID(), secondElement.getLabelID());
                        return message;
                    }
                }
            }
        }
        return "";
    }

    /**
     * 校验be关联枚举字段，不允许有相同编号
     *
     * @param model 业务实体be
     * @return 错误提示
     */
    private String validateAssociateEnum(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        List<IGspCommonObject> allObjectList = model.getAllObjectList();
        for (IGspCommonObject iGspCommonObject : allObjectList) {
            List<IGspCommonElement> elementList = iGspCommonObject.getAllElementList(false);
            // 获取be内枚举字段的编号及名称对应关系
            Map<String, String> elementCodeName = getElementCodeName(elementList);
            if (elementCodeName.isEmpty()) {
                // 无枚举、关联字段，跳过检查
                continue;
            }
            for (IGspCommonElement iGspCommonElement : elementList) {
                if (iGspCommonElement.getObjectType() == GspElementObjectType.Association) {
                    List<GspAssociation> elementAssociation = iGspCommonElement.getChildAssociations();
                    validateEnum(elementCodeName, elementAssociation, iGspCommonElement.getName(), sb);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 获取枚举、关联字段中编号对应的名称
     *
     * @param elementList be业务实体
     * @return 编号对应名称
     */
    private Map<String, String> getElementCodeName(List<IGspCommonElement> elementList) {
        Map<String, String> elementCodeName = new HashMap<>();
        for (IGspCommonElement iGspCommonElement : elementList) {
            if (iGspCommonElement.getObjectType() == GspElementObjectType.Enum || iGspCommonElement.getObjectType() == GspElementObjectType.Association) {
                elementCodeName.put(iGspCommonElement.getCode(), iGspCommonElement.getName());
            }
        }
        return elementCodeName;
    }

    /**
     * 判断关联关系中枚举、关联字段和be中是否存在相同编号
     *
     * @param elementCodeName 编号对应名称
     * @param elementAssociation 关联关系
     * @param eleName 关联字段名称
     * @param sb 错误提示
     */
    private void validateEnum(Map<String, String> elementCodeName, List<GspAssociation> elementAssociation, String eleName, StringBuilder sb) {
        for (GspAssociation gspAssociation : elementAssociation) {
            List<IGspCommonField> refElementList = gspAssociation.getRefElementCollection();
            for (IGspCommonField refElement : refElementList) {
                if (refElement.getObjectType() == GspElementObjectType.Enum || refElement.getObjectType() == GspElementObjectType.Association) {
                    if (elementCodeName.containsKey(refElement.getCode())) {
                        // 存在枚举类型和关联枚举编号相同
                        String elementName = elementCodeName.get(refElement.getCode());
                        sb.append(String.format(ASSOCIATION_ENUM, eleName, refElement.getName(), elementName, elementName));
                        sb.append("\n");
                    }
                }
            }
        }
    }

    ///#region Model
    // 检查数据模型的基本信息
    private String validateModelBasicInfo(GspBusinessEntity model, String path) {
        StringBuilder sb = new StringBuilder();
        if (CheckInfoUtil.checkNull(model.getCode())) {
            sb.append(String.format(MODEL + "的编号不能为空! ", model.getName()));
        } else {
            // 模型Code限制非法字符
            if (!ConformToNaminGspecification(model.getCode())) {
                sb.append(String.format(MODEL + "的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", model.getName()));
                sb.append("\n");
            }
        }
        if (CheckInfoUtil.checkNull(model.getName())) {
            sb.append(String.format(MODEL + "的名称不能为空! ", model.getCode()));
        }

        //todo:[启用时间戳]方案成熟前，先隐藏
        //if (!model.IsUsingTimeStamp)
        //{
        //	// 若传入路径不为空，则检查旧be的值
        //	if (!string.IsNullOrEmpty(path))
        //	{
        //		//旧be中的启用时间戳为true，且已经生成dbo,则不允许设置为false
        //		var service = ServiceManager.GetService<IMetadataService>();
        //		var oldBeMetadata = service.GetRefMetadata(path, model.ID, null);
        //		var oldBe = oldBeMetadata.Content as GspBusinessEntity;
        //		if (oldBe != null && oldBe.IsUsingTimeStamp && !string.IsNullOrEmpty(oldBe.MainObject.RefObjectName))
        //		{
        //			sb.append(String.format("已生成dbo的实体，不允许将[启用时间戳]属性由true改为false。");
        //		}
        //	}
        //}
        if (model.getEnableCaching() && CheckInfoUtil.checkNull(model.getCacheConfiguration())) {
            sb.append(String.format(MODEL + "启用缓存之后，缓存配置不能为空。", model.getName()));
        }
        if (model.getCode().equals(model.getGeneratingAssembly())) {
            sb.append(String.format(MODEL + "编号不可与程序集名相同。", model.getName()));
        }
        if (!CheckInfoUtil.checkNull(model.getVersionContronInfo().getVersionControlElementId())) {

            IGspCommonField ele = model.getMainObject().findElement(model.getVersionContronInfo().getVersionControlElementId());
            if (ele == null) {
                sb.append(String.format(MODEL + "设置的版本字段不存在，请重新设置。", model.getName()));
            } else if (ele.getMDataType() != GspElementDataType.DateTime) {
                sb.append(String.format(MODEL + "设置的版本字段应为[日期时间]类型，当前版本字段'{%2$s}'数据类型为'{%3$s}'，请修改。", model.getName(), ele.getName(), ele.getMDataType().toString()));
            }
        }
        return sb.toString();
    }

    private String validateVarableEntity(GspCommonModel model) {
        StringBuilder sb = new StringBuilder();
        //validateObjectBasicInfo(model.Variables,sb,model.Name);
        sb.append(validateVariables(model));
        return sb.toString();
    }

    private String validateVariables(GspCommonModel model) {

        CommonVariableCollection vars = model.getVariables().getContainElements();
        StringBuilder sb = new StringBuilder();
        if (vars != null && vars.size() > 0) {

            for (IGspCommonField variable : vars) {
                // 检查元素的基本信息
                validateElementBasicInfo(variable, sb, model.getName(), "变量集合", "变量集合", model.getIsVirtual(), VARIABLE);
            }

            // 编号不可重复
            for (int i = 0; i < vars.size() - 1; i++) {
                IGspCommonField firstElement = vars.getItem(i);
                for (int j = i + 1; j < vars.size(); j++) {
                    IGspCommonField secondElement = vars.getItem(j);
                    if (firstElement.getCode().equals(secondElement.getCode()) && firstElement.getBelongObject().getID().equals(secondElement.getBelongObject().getID())) {
                        String message = String.format("业务实体 '%1$s' 的'变量集合' 中字段 '%2$s' 和字段 '%3$s' 的 [编号] 属性不允许重复! ", model.getName(), firstElement.getName(), secondElement.getName());
                        return message;
                    }
                }
            }
        }

        //联动计算
        CommonDtmCollection dtms = new CommonDtmCollection();
        dtms.addAll(model.getVariables().getDtmAfterCreate());
        dtms.addAll(model.getVariables().getDtmAfterModify());
        dtms.addAll(model.getVariables().getDtmBeforeSave());
        sb.append(validateVarDtms(dtms, model.getName()));

        return sb.toString();
    }

    private String validateVarDtms(CommonDtmCollection collection, String modelName) {
        //联动计算
        String errorMessage = String.format(VARIABLE_DTM, modelName);

        List<CommonOperation> dtms = collection.stream().collect(Collectors.toList());
//        ArrayList<CommonDetermination> dtms = collection.getAllItems(item-> {return true;});
        //①必填项
        StringBuilder sb = new StringBuilder();
        sb.append(validateCommonOperationBasicInfo(errorMessage, (ArrayList<CommonOperation>) dtms));
        if (sb.length() > 0) {
            return sb.toString();
        }
        //②编号重复
        sb.append(String.format(validateCommonOperationCodeRepeat(errorMessage, (ArrayList<CommonOperation>) dtms)));
        return sb.toString();
    }


    ///#endregion


    ///#region Object

    private void validateObjectBasicInfo(IGspCommonDataType aObject, StringBuilder sb, String modelName, String path) {
        if (CheckInfoUtil.checkNull(aObject.getCode())) {
            sb.append(String.format(OBJECT + "的编号不能为空! ", modelName, aObject.getName()));
        } else {
            // 对象Code限制非法字符
            if (!ConformToNaminGspecification(aObject.getCode())) {
                sb.append(String.format(OBJECT + "的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", modelName, aObject.getName()));
                sb.append("\n");
            }
            // 对象Code限制数据库保留字
            if (!CheckUtil.isLegality(aObject.getCode()))
            {
                sb.append(String.format(OBJECT + "的 [编号] '{%3$s}'是Java关键字,请修改！ ",
                    modelName, aObject.getName(), aObject.getCode()));
                sb.append("\n");
            }
        }
        if (CheckInfoUtil.checkNull(aObject.getName())) {
            sb.append(String.format(OBJECT + "的名称不能为空! ", modelName, aObject.getCode()));
        }
        GenerateFromDbo generateFromDbo = GenerateFromDbo.getInstance();
        String appCode = generateFromDbo.GetAppCode(path);
        String dboCode = appCode + aObject.getCode();
        if (dboCode.length() > 30) {
            sb.append(String.format(OBJECT + "对应的dbo编号'{%3$s}'的长度不能超过30! ", modelName, aObject.getName(), dboCode));
        }
    }

    // 检查数据模型中对象的基本信息
    private String validateObjectBasicInfo(GspBusinessEntity model, String path) {
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();
        for (IGspCommonObject aObject : aObjectList) {
            validateObjectBasicInfo(aObject, sb, model.getName(), path);
        }

        for (IGspCommonObject aObject : aObjectList) {
            for (IGspCommonObject bObject : aObjectList) {
                // 排除本身
                if (aObject.getID().compareTo(bObject.getID()) == 0) {
                    continue;
                }

                if (aObject.getID().compareTo(bObject.getCode()) == 0) {
                    sb.append(String.format(OBJECT + "节点'{%2$s}'的编号相同，请修改。", model.getName(), aObject.getName(), bObject.getName()));
                    return sb.toString();
                }
            }
        }

        return sb.toString();
    }

    // 检查主对象ID字段
    private String validateIDElement(GspBusinessEntity model) {
        GspBizEntityObject mObject = model.getMainObject();
        //验证ID字段和Code字段不能有引用和枚举。并且必须必填和插入, 更新必须为false
        GspBizEntityElement idElement = (GspBizEntityElement) ((mObject.getIDElement() instanceof GspBizEntityElement) ? mObject.getIDElement() : null);

        StringBuilder sb = new StringBuilder();
        if (idElement.getHasAssociation()) {
            sb.append(String.format(FIELD + "作为ID字段, 其 [对象类型] 属性不能为引用类型! ", model.getName(), mObject.getName(), idElement.getName()));
            sb.append("\n");
        } else if (idElement.getObjectType() == GspElementObjectType.Enum) {
            sb.append(String.format(FIELD + "作为ID字段, 其 [对象类型] 属性不能为枚举类型! ", model.getName(), mObject.getName(), idElement.getName()));
            sb.append("\n");
        }
        if (!idElement.getIsRequire()) {
            sb.append(String.format(FIELD + "作为ID字段, 其 [是否必须] 属性必须选'是'! ", model.getName(), mObject.getName(), idElement.getName()));
            sb.append("\n");
        }
        //ID字段长度及字段数据类型校验
        if (!validateIDElementTypeAndLength(idElement)) {
            sb.append(String.format(FIELD + "作为ID字段, 其字段类型应为[字符串], [长度] 属性应大于36! ", model.getName(), mObject.getName(), idElement.getName()));
            sb.append("\n");
        }
        return sb.toString();
    }

    // 模型中的主对象的分级信息
//    private String validateObjectHiberarchyInfo(GspBusinessEntity model)
//    {
//        GspBizEntityObject mObject = model.getMainObject();
//        StringBuilder sb = new StringBuilder();
//        if ((mObject.HirarchyInfo != null && mObject.HirarchyInfo.LayerElement != null && mObject.HirarchyInfo.PathElement != null && mObject.HirarchyInfo.IsDetailElement != null) || (mObject.HirarchyInfo != null && mObject.HirarchyInfo.LayerElement != null && mObject.HirarchyInfo.ParentElement != null && mObject.HirarchyInfo.IsDetailElement != null))
//        {
//            if ((mObject.HirarchyInfo.PathElement != null) && (mObject.HirarchyInfo.LayerElement.ID == mObject.HirarchyInfo.PathElement.ID))
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的级数字段与分级码字段不能选择同一字段! ", model.getName(), mObject.getName());
//                sb.append("\n");
//            }
//
//            if ((mObject.HirarchyInfo.ParentElement != null) && (mObject.HirarchyInfo.LayerElement.ID == mObject.HirarchyInfo.ParentElement.ID))
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的级数字段与父路径字段不能选择同一字段! ", model.getName(), mObject.getName());
//                sb.append("\n");
//            }
//
//            if (mObject.HirarchyInfo.LayerElement.ID == mObject.HirarchyInfo.IsDetailElement.ID)
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的级数字段与是否明细字段不能选择同一字段! ", model.getName(), mObject.getName());
//                sb.append("\n");
//            }
//
//            if ((mObject.HirarchyInfo.PathElement != null) && (mObject.HirarchyInfo.PathElement.ID == mObject.HirarchyInfo.IsDetailElement.ID))
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的分级码字段与是否明细字段不能选择同一字段! ", model.getName(), mObject.getName());
//                sb.append("\n");
//            }
//
//            if ((mObject.HirarchyInfo.ParentElement != null) && (mObject.HirarchyInfo.ParentElement.ID == mObject.HirarchyInfo.IsDetailElement.ID))
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的父路径字段与是否明细字段不能选择同一字段! ", model.getName(), mObject.getName());
//                sb.append("\n");
//            }
//
//            if (mObject.HirarchyInfo.LayerElement != null && mObject.HirarchyInfo.LayerElement.MDataType != GspElementDataType.Integer)
//            {
//                sb.append(String.format(OBJECT + "的 [分级信息] 属性的级数字段必须为整型! ", model.getName(), mObject.getName());
//            }
//        }
//        return sb.toString();
//    }


    ///#endregion


    ///#region Element

    private String validateElementDefaultValue(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        String regexInt = "^-?\\d+$"; //判断整数，负值也是整数

        Pattern patternInt = Pattern.compile(regexInt);

        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();
        for (IGspCommonObject aObject : aObjectList) {
            java.util.ArrayList<IGspCommonElement> elementList = aObject.getAllElementList(false);
            for (IGspCommonElement ele : elementList) {
                boolean isvalidate = true;
                if (ele.getDefaultValueType() == ElementDefaultVauleType.Expression) {
                    validateElementExpression(ele, sb, model.getName(), aObject.getName());
                    continue;
                }
                GspElementDataType type = ele.getMDataType();
                String value = ele.getDefaultValue();
                int length = ele.getLength();

                if (!CheckInfoUtil.checkNull(value)) {
                    switch (type) {
                        case String:
                        case Text:
                            break;
                        case Integer:
                            Matcher matcherInt = patternInt.matcher(value);
                            if (matcherInt.matches()) {
                                isvalidate = true;
                            } else {
                                isvalidate = false;
                            }
                            break;
                        case Decimal:
                            String reDecimalString = String.format("^(([0-9]+\\.[0-9]{0,%1$s})|([0-9]*\\.[0-9]{0,%1$s})|([1-9][0-9]+)|([0-9]))$", ele.getPrecision());
                            Pattern patternDecimal = Pattern.compile(reDecimalString);
                            Matcher matcherDecimal = patternDecimal.matcher(value);
                            if (matcherDecimal.matches()) {
                                isvalidate = true;
                            } else {
                                //isvalidate = false;
                                sb.append(String.format(FIELD + "的[默认值] 与[数据类型] 不匹配，请检查是否为[浮点数字]，请检查[精度]是否匹配! ", model.getName(), aObject.getName(), ele.getName()));
                                sb.append("\n");
                                return sb.toString();
                            }
                            break;
                        case Date:
                            try {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                                Date date=sdf.parse(value);
                                isvalidate = true;
                            } catch (java.lang.Exception e) {
                                isvalidate = false;
                            }
                            break;
                        case DateTime:
                            try {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                Date date=sdf.parse(value);
                                isvalidate = true;
                            } catch (java.lang.Exception e) {
                                isvalidate = false;
                            }
                            break;
                        case Boolean:
                            if (value.toUpperCase().equals("True".toUpperCase()) || value.toUpperCase().equals("False".toUpperCase())) {
                                isvalidate = true;
                            } else {
                                isvalidate = false;
                            }
                            break;
                        case Binary:
                            if (value.trim().equals("")) {
                                isvalidate = true;
                            } else {
                                isvalidate = false;
                            }
                            break;
                        default:
                            break;
                    }
                }
                if (!isvalidate) {
                    sb.append(String.format(FIELD + "的 [默认值] 与 [数据类型] 不匹配! ", model.getName(), aObject.getName(), ele.getName()));
                    sb.append("\n");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 校验be字段表达式类型默认值校验
     *
     * @param ele be字段
     * @param sb 错误提示
     * @param modelName 工程名称
     * @param aObjectName be名称
     */
    private void validateElementExpression(IGspCommonElement ele, StringBuilder sb, String modelName,
        String aObjectName) {
        String expression = ele.getDefaultValue();
        if (ExpressionVariableCheckUtil.isDateType(expression)) {
            if (ele.getMDataType() == GspElementDataType.Date || ele.getMDataType() == GspElementDataType.DateTime) {
                return;
            }
            sb.append(String.format(EXPRESSION + "的数据类型与表达式类型不相符,请选择文本类型的表达式。", modelName, aObjectName, ele.getName()));
            sb.append("\n");
        }
        if (ExpressionVariableCheckUtil.isTextType(expression)) {
            if (ele.getMDataType() == GspElementDataType.String || ele.getMDataType() == GspElementDataType.Text) {
                return;
            }
            sb.append(String.format(EXPRESSION + "的数据类型与表达式类型不相符,请选择时间类型的表达式。", modelName, aObjectName, ele.getName()));
            sb.append("\n");
        }
    }

    private String validateElementLabelID(GspBusinessEntity model) {
        java.util.ArrayList<IGspCommonElement> allElementList = model.getAllElementList(true);

        if (allElementList != null && allElementList.size() > 0) {
            for (int i = 0; i < allElementList.size() - 1; i++) {
                IGspCommonElement firstElement = allElementList.get(i);
                for (int j = i + 1; j < allElementList.size(); j++) {
                    IGspCommonElement secondElement = allElementList.get(j);
                    if (firstElement.getLabelID().equals(secondElement.getLabelID()) && firstElement.getBelongObject().getID().equals(secondElement.getBelongObject().getID())) {
                        String message = String.format("业务实体 '%1$s' 的节点 '%2$s' 中字段 '%3$s' 和字段 '%4$s' 的 [标签] 属性不允许重复! ", model.getName(), firstElement.getBelongObject().getName(), firstElement.getName(), secondElement.getName());
                        return message;
                    }
                }
            }
        }
        return "";
    }

    private String validateElementCode(GspBusinessEntity model) {
        java.util.ArrayList<IGspCommonElement> allElementList = model.getAllElementList(false);
        if (allElementList != null && allElementList.size() > 0) {
            for (int i = 0; i < allElementList.size() - 1; i++) {
                IGspCommonElement firstElement = allElementList.get(i);
                for (int j = i + 1; j < allElementList.size(); j++) {
                    IGspCommonElement secondElement = allElementList.get(j);
                    if (firstElement.getCode().equals(secondElement.getCode()) && firstElement.getBelongObject().getID().equals(secondElement.getBelongObject().getID())) {
                        String message = String.format("业务实体 '%1$s' 的节点 '%2$s' 中字段 '%3$s' 和字段 '%4$s' 的 [编号] 属性不允许重复! ", model.getName(), firstElement.getBelongObject().getName(), firstElement.getName(), secondElement.getName());
                        return message;
                    }
                }
            }
        }
        return "";
    }

    // 关联关系
    private String validateChildRelation(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        GspBizEntityObject mainObject = model.getMainObject();
        if (mainObject != null) {
            for (IGspCommonObject cObject : mainObject.getContainChildObjects()) {
                String message = "";
                if (cObject.getKeys().size() == 0) {
                    sb.append(String.format(OBJECT + "与父节点 %2$s 缺少关联关系! 请添加! ", model.getName(), cObject.getName(), cObject.getParentObject().getName()));
                    sb.append("\n");
                }
                //if (cObject.KeyCollections.Count >= 2)
                //{
                //    sb.append(String.format(OBJECT + "与父对象 '{2}' 存在多关联关系! 目前不支持多关联! ", model.Name, cObject.Name, cObject.ParentObject.Name);
                //    sb.AppendLine();
                //}

                //验证ID字段不能即是主键又是外键
                String cID = cObject.getColumnGenerateID().getElementID();
                GspAssociationKey ak = cObject.getKeys().get(0);
                if (cID.equals(ak.getSourceElement())) {
                    sb.append(String.format(OBJECT + "与父节点 '{%3$s}' 的关联关系违反外键约束! '{%4$s}' 不能为主键! ", model.getName(), cObject.getName(), cObject.getParentObject().getName(), ak.getSourceElementDisplay()));
                    sb.append("\n");
                }

                //ParentID字段应为ID类型
                if (!validateIDElementTypeAndLength(cObject.getParentObject().findElement(ak.getSourceElement()))) {
                    sb.append(String.format(OBJECT + "与父节点 '{%3$s}' 的关联关系字段{%4$s}不符合ID字段类型，字段类型应为字符串，长度36! ", model.getName(), cObject.getName(), cObject.getParentObject().getName(), ak.getSourceElementDisplay()));
                    sb.append("\n");
                }

                if ((mainObject.getCode().trim().toUpperCase() + "LIST").equals(cObject.getCode().trim().toUpperCase())) {
                    sb.append(String.format(OBJECT + "的编号不能为 '主节点编号+LIST' 的形式! ", model.getName(), cObject.getName(), cObject.getParentObject().getName(), ak.getSourceElementDisplay()));
                    sb.append("\n");
                }

                message = validateChildrenRelation(model, cObject);
                if (message.length() > 0) {
                    return message;
                }
            }
        }
        return sb.toString();
    }

    /**
     * 逻辑删除字段
     *
     * @param model
     * @return
     */
    private String validateLogicDeleteElement(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<IGspCommonObject> collection = model.getAllObjectList();

        for (IGspCommonObject cObject : collection) {
            String message = "";
            GspBizEntityObject bizEntityObject = (GspBizEntityObject) cObject;
            LogicDeleteControlInfo info = bizEntityObject.getLogicDeleteControlInfo();
            if (!info.getEnableLogicDelete()) {
                continue;
            }
            String logicDeleteElementId = info.getLogicDeleteControlElementId();
            if (CheckInfoUtil.checkNull(logicDeleteElementId)) {
                sb.append(String.format(OBJECT + "中启用删除检查，但是未选择删除检查字段! ", model.getName(), cObject.getName()));
                sb.append("\n");
                continue;
            }

            IGspCommonElement ele = bizEntityObject.findElement(logicDeleteElementId);
            if (ele == null) {
                // 配置，但是字段没了
                sb.append(String.format(OBJECT + "中启用删除检查，但是配置的删除检查字段不存在！", model.getName(), cObject.getName()));
                sb.append("\n");
                continue;
            }
            if (ele.getMDataType() != GspElementDataType.Boolean) {
                // 配置，但是字段数据类型错误
                sb.append(String.format(OBJECT + "中启用删除检查，但是配置的删除检查字段不是布尔类型！", model.getName(), cObject.getName()));
                sb.append("\n");
                continue;
            }
        }
        return sb.toString();
    }

    /**
     * 校验ID类型字段类型字符串且长度为22
     * ID字段，ParentID字段，关联字段
     * TODO:被关联字段暂不考虑
     *
     * @param element
     * @return
     */
    private boolean validateIDElementTypeAndLength(IGspCommonField element) {
        if (element == null) {
            return true;
        }
        return element.getMDataType() == GspElementDataType.String && element.getLength() >= 36;
    }

    private String validateChildrenRelation(GspBusinessEntity model, IGspCommonObject cObject) {
        StringBuilder sb = new StringBuilder();
        if (cObject.getContainChildObjects() != null && cObject.getContainChildObjects().size() > 0) {
            for (int i = 0; i < cObject.getContainChildObjects().size(); i++) {
                IGspCommonObject ccObject = cObject.getContainChildObjects().get(i);
                if (ccObject.getKeys().size() == 0) {
                    sb.append(String.format(OBJECT + "与父节点 '{2}' 缺少关联关系! 请添加! ", model.getName(), ccObject.getName(), ccObject.getParentObject().getName()));
                    sb.append("\n");
                }

                String cID = ccObject.getColumnGenerateID().getElementID();

                GspAssociationKey ak = ccObject.getKeys().get(0);
                if (cID.equals(ak.getSourceElement())) {
                    sb.append(String.format(OBJECT + "与父节点 '{2}' 的关联关系违反外键约束! '{3}' 不能为主键! ", model.getName(), ccObject.getName(), ccObject.getParentObject().getName(), ak.getSourceElementDisplay()));
                    sb.append("\n");
                }

                String message = validateChildrenRelation(model, ccObject);
                if (message.length() > 0) {
                    sb.append(String.format(message));
                    sb.append("\n");
                    break;
                }
            }
        }
        return sb.toString();
    }

    private void validateElementBasicInfo(IGspCommonField element, StringBuilder sb, String modelName, String objName, String objCode, boolean modelIsVirtual, String errorMessage) {
        if (CheckInfoUtil.checkNull(element.getCode())) {
            sb.append(String.format(errorMessage + "的 [编号] 属性不允许为空! ", modelName, objName, element.getName()));
            sb.append("\n");
        } else {
            // 字段Code限制非法字符
            if (!ConformToNaminGspecification(element.getCode())) {
                sb.append(String.format(errorMessage + "的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", modelName, objName, element.getName()));
                sb.append("\n");
            }
            // 字段Code限制数据库保留字
            ReserveResult codeResult = getReservedResult(element.getCode(), errorMessage, modelName, objName, "编号", element);
            if(codeResult.isKeyWords){
                sb.append(codeResult.message);
                sb.append("\n");
            }
            else{
                ReserveResult labelIdResult = getReservedResult(element.getLabelID(), errorMessage, modelName, objName, "标签", element);
                if(labelIdResult.isKeyWords){
                    sb.append(labelIdResult.message);
                    sb.append("\n");
                }
            }

            // 字段Code限制数据库对象保留字（包括1.时间戳字段；2.租户字段TenantID；）
            if (isDatabaseObjectReservedWords(element.getCode())) {
                sb.append(String.format(errorMessage + "的 [编号] '%3$s'为数据库对象保留字（时间戳字段或租户字段TenantID），请修改。 ", modelName, objName, element.getName(), element.getCode()));
                sb.append("提示：若希望启用时间戳字段，可在Tab基本信息中，勾选[启用时间戳]。");
                sb.append("\n");
            }
            // 字段LabelID限制数据库对象保留字（包括1.时间戳字段；2.租户字段TenantID；）
            else if (isDatabaseObjectReservedWords(element.getLabelID())) {
                sb.append(String.format(errorMessage + "的 [标签] '%3$s'为数据库对象保留字（时间戳字段或租户字段TenantID），请修改。 ", modelName, objName, element.getName(), element.getLabelID()));
                sb.append("提示：若希望启用时间戳字段，可在Tab基本信息中，勾选[启用时间戳]。");
                sb.append("\n");
            }
        }
        if (CheckInfoUtil.checkNull(element.getName())) {
            sb.append(String.format(errorMessage + "的 [名称] 属性不允许为空! ", modelName, objName, element.getCode()));
            sb.append("\n");
        }

        if (CheckInfoUtil.checkNull(element.getLabelID()) || CheckInfoUtil.checkNull(element.getLabelID().trim())) {
            if (modelIsVirtual) {
                element.setLabelID(element.getCode());
            } else {
                sb.append(String.format(errorMessage + "的 [标签] 属性不允许为空! ", modelName, objName, element.getName()));
                sb.append("\n");
            }
        } else {
            if (element.getLabelID() == objCode + "_Id") {
                sb.append(String.format(errorMessage + "的标签不能是节点的编号+'_Id'。", modelName, objName, element.getName())).append("\r\n");
            }
            if (element.getLabelID().length() > 30) {
                //sb.append(String.format(errorMessage + "的 [标签] 属性的长度不能超过30个字符! ", modelName, objName, element.Name);
                sb.append(String.format(errorMessage + "[编号]属性的长度不能超过30.", modelName, objName, element.getName()));
                sb.append("\n");
//                sb.append(String.format("即“对象编号.字段标签”的长度不能超过30。 "));
//                sb.append("\n");
            }

            // LabelID在表单和报表中用作XML的标签，要限制非法字符
            if (!ConformToNaminGspecification(element.getLabelID())) {
                sb.append(String.format(errorMessage + "的 [标签] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", modelName, objName, element.getName()));
                sb.append("\n");
            } else if (isFrameworkReservedWords(element.getLabelID())) {
                sb.append(String.format(errorMessage + "的 [标签] '{%3$s}'为系统保留字，请修改。", modelName, objName, element.getName(), element.getLabelID()));
                sb.append("\n");
            }
        }
        if (element.getObjectType() == GspElementObjectType.Association) {
            //关联字段必须满足ID字段类型
//            if (!validateIDElementTypeAndLength(element)) {
//                sb.append(String.format(errorMessage + "的 [对象类型] 属性为关联, 应满足ID字段类型，字段数据类型为[字符串], 并且[长度]为36! ", modelName, objName, element.getName()));
//                sb.append("\n");
//            }

            if (!element.getHasAssociation()) {
                sb.append(String.format(errorMessage + "的 [对象类型] 属性为关联, [关联] 属性不允许为空! ", modelName, objName, element.getName()));
                sb.append("\n");
            } else {
                for (GspAssociation association : element.getChildAssociations()) {
                    if (association == null || association.getKeyCollection().size() == 0) {
                        sb.append(String.format(errorMessage + "的 [对象类型] 属性为关联, [关联] 属性不允许为空! ", modelName, objName, element.getName()));
                        sb.append("\n");
                    }
                    if(StringUtils.isEmpty(association.getRefModelID())){
                        sb.append(String.format(errorMessage + "的 [对象类型] 属性为关联, [关联模型] 属性不允许为空! ", modelName, objName, element.getName()));
                        sb.append("\n");
                    }
                    if(StringUtils.isEmpty(association.getRefObjectID())){
                        sb.append(String.format(errorMessage + "的 [对象类型] 属性为关联, [关联节点] 属性不允许为空! ", modelName, objName, element.getName()));
                        sb.append("\n");
                    }
                    //处理有时关联字段会丢失的问题
                    String sourceElement = "";
                    for (GspAssociationKey associationKey : association.getKeyCollection()) {
                        if (associationKey.getSourceElement().length() == 0 || associationKey.getTargetElement().length() == 0) {
                            sb.append(String.format(errorMessage + "的引用元素丢失! ", modelName, objName, element.getName()));
                            sb.append("\n");
                        }
                        else{
                            sourceElement = associationKey.getSourceElement();
                            String targetElement = associationKey.getTargetElement();
                            if(!element.getID().equalsIgnoreCase(targetElement)){
                                sb.append(String.format(errorMessage + "的关联属性[targetElement]值应为当前字段ID! ", modelName, objName, element.getName()));
                                sb.append("\n");
                            }
                        }
                    }

                    GspMetadata refMetadata = getMetadataService().getRefMetadata(association.getRefModelID());
                    if(refMetadata == null){
                        sb.append(String.format(errorMessage + "关联的元数据未找到", modelName, objName, element.getName()));
                        sb.append("\n");
                    }
                    else {
                        if(refMetadata.getContent() instanceof GspBusinessEntity){
                            GspBusinessEntity refBusinessEntity = (GspBusinessEntity) refMetadata.getContent();
                            IGspCommonObject refObject = refBusinessEntity.findObjectById(association.getRefObjectID());
                            if(refObject == null){
                                sb.append(String.format(errorMessage + "关联的节点未找到", modelName, objName, element.getName()));
                                sb.append("\n");
                            }
                            else{
                                if(refObject.findElement(sourceElement) == null){
                                    sb.append(String.format(errorMessage + "关联的字段未找到", modelName, objName, element.getName()));
                                    sb.append("\n");
                                }
                                for(IGspCommonField commonField:association.getRefElementCollection()){
                                    IGspCommonElement refElement = refObject.findElement(commonField.getRefElementId());

                                    if(refElement == null){
                                        sb.append(String.format(errorMessage + "带出字段'{%4$s}'在关联模型上未找到", modelName, objName, element.getName(), commonField.getLabelID()));
                                        sb.append("\n");
                                    }
                                    else {
                                        if(commonField.getRefElementId().equalsIgnoreCase(element.getID()) && element.getBelongObject().getID().equals(refObject.getID())){
                                            //if太长了 model的判断放到方法内部
                                            GspCommonObject currentObj = null;
                                            if(element.getBelongObject() instanceof GspCommonObject){
                                                currentObj = (GspCommonObject) element.getBelongObject();
                                            }
                                            if(currentObj != null && currentObj.getBelongModel().getID().equals(association.getRefModelID())){
                                                sb.append(String.format(errorMessage + "带出字段不能包含自己", modelName, objName, element.getName()));
                                                sb.append("\n");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } else if (element.getObjectType() == GspElementObjectType.Enum) {
            //todo 暂时屏蔽、后续要加上，前端放开
            // 枚举类型字段，校验默认值为枚举编号
//            if (!CheckInfoUtil.checkNull(element.getDefaultValue()))
//            {
//                String defaultValue = element.getDefaultValue();
//                boolean isEnumKey = false;
//                for (GspEnumValue enumValue : element.getContainEnumValues())
//                {
//                    if (defaultValue.equals(enumValue.getValue()))
//                    {
//                        isEnumKey = true;
//                    }
//                }
//                if (!isEnumKey)
//                {
//                    sb.append(String.format(errorMessage + "的 [对象类型] 属性为枚举, [默认值] 应为枚举编号。 ", modelName,objName, element.getName()));
//                }
//            }
            // 枚举类型字段，非必填
            if (element.getIsRequire()) {
                sb.append(String.format(errorMessage + "的 [对象类型] 属性为枚举, [是否必填] 属性应为否。 ", modelName, objName, element.getName()));
                sb.append("\n");
            }

            if (element.getContainEnumValues() == null || element.getContainEnumValues().size() == 0) {
                sb.append(String.format(errorMessage + "的 [对象类型] 属性为枚举, [枚举] 属性不允许为空! ", modelName, objName, element.getName()));
                sb.append("\n");
            }

            //处理Enum值必须为string的问题
            for (GspEnumValue ev : element.getContainEnumValues()) {
                String _value = ev.getValue();
                if (element.getMDataType() == GspElementDataType.Boolean) {
                    try {
                        boolean temp = Boolean.parseBoolean(_value);
                    } catch (java.lang.Exception e) {
                        sb.append(String.format(errorMessage + "的 [枚举] 属性中的枚举值["+_value+"]应该为布尔值! ", modelName, objName, element.getName()));
                        sb.append("\n");
                    }
                }
//                else if (element.getMDataType() == GspElementDataType.Integer) {
//                    try {
//                        int temp = Integer.parseInt(ev.getIndex());
//                    } catch (java.lang.Exception e) {
//                        sb.append(String.format(errorMessage + "的 [枚举] 属性中的枚举值["+_value+"]应该为整数! ", modelName, objName, element.getName()));
//                        sb.append("\n");
//                    }
//                }
                else if (element.getMDataType() == GspElementDataType.String) {
                    int indexLength = String.valueOf(ev.getIndex()).length();
                    int eleLength = element.getLength();
                    if (eleLength < indexLength) {
                        sb.append(String.format(errorMessage + "的 [枚举值]'{%3$s}' 中的索引长度应小于等于字段长度! ", modelName, objName, element.getName(), ev.getName()));
                        sb.append("\n");
                    }
                }
            }
            if (element.getContainEnumValues() != null && element.getContainEnumValues().size() > 0) {
                for (int i = 0; i < element.getContainEnumValues().size() - 1; i++) {

                    GspEnumValue enumValue1 = element.getContainEnumValues().get(i);
                    for (int j = i + 1; j < element.getContainEnumValues().size(); j++) {

                        GspEnumValue enumValue2 = element.getContainEnumValues().get(j);
                        if (enumValue1.getName() == enumValue2.getName()) {
                            String message = String.format(errorMessage + "的枚举编号'{0}'重复，重复编号为：【"+enumValue1.getName()+"】", modelName, objName, element.getName(), enumValue1.getName());
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                }
            }
        } else if (element.getObjectType() == GspElementObjectType.DynamicProp) {
            if (element.getDynamicPropSetInfo() != null && element.getDynamicPropSetInfo().getDynamicPropSerializerComp() != null && CheckInfoUtil.checkNull(element.getDynamicPropSetInfo().getDynamicPropSerializerComp().getId())) {
                sb.append(String.format(errorMessage + "的 [序列化构件] 不允许为空! ", modelName, objName, element.getName()));
            }
        }

        if (element.getMDataType() == GspElementDataType.Decimal) {
            if (element.getLength() == 0) {
                sb.append(String.format(errorMessage + "[数据类型] 为[浮点数字]，其 [长度] 不可为0. ", modelName, objName, element.getName()));
                sb.append("\n");
            }

            if (element.getPrecision() == 0) {
                sb.append(String.format(errorMessage + "[数据类型] 为[浮点数字]，其 [精度] 不可为0. ", modelName, objName, element.getName()));
                sb.append("\n");
            }

        }
        if (element.getMDataType() == GspElementDataType.String) {
            if(!element.getIsVirtual() && element.getLength() < 1) {
                sb.append(String.format(errorMessage + "[数据类型] 为[文本], 其 [长度] 大于1. ", modelName, objName, element.getName()));
                sb.append("\n");
            }
            if(element.getIsVirtual() && element.getLength() < 0)
            {
                sb.append(String.format(errorMessage + "[数据类型] 为[文本], 其 [长度] 大于0. ", modelName, objName, element.getName()));
                sb.append("\n");
            }
        }
        String errorMessageString = String.format(errorMessage, modelName, objName, element.getName());
        if (element.getIsUdt() && CheckInfoUtil.checkNull(element.getUdtID())) {
            sb.append(String.format(FIELD + "的数据类型为[业务字段]，请配置其对应的业务字段。", modelName, objName, element.getName()));
            sb.append("\n");
        }
        //20190918盘，临时添加检查：
        //Bug296009,按udtID加载出udt元数据来，看是否为多列的多值udt
        //Bug296448,udt的带出字段包含[普通关联]类型的
        if (element.getObjectType() == GspElementObjectType.Association) {

            for (IGspCommonField refEle : element.getChildAssociations().get(0).getRefElementCollection()) {
                if (refEle.getIsUdt()) {

                    String refEleUdtId = refEle.getUdtID();
                    if (CheckInfoUtil.checkNull(refEleUdtId)) {
                        throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0022, errorMessageString, refEle.getLabelID());
                    }

                    GspMetadata refEleUdtMeta = getMetadataService().getRefMetadata(refEleUdtId);
                    if (refEleUdtMeta == null) {
                        throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0023, errorMessageString, refEle.getLabelID(), refEleUdtId);
                    }

//                    UnifiedDataTypeDef refUdtContent = (UnifiedDataTypeDef) ((refEleUdtMeta.getContent() instanceof UnifiedDataTypeDef) ? refEleUdtMeta.getContent() : null);
//                    if (refUdtContent instanceof ComplexDataTypeDef) {
//                        if (((ComplexDataTypeDef) refUdtContent).getDbInfo().getMappingType() == ColumnMapType.MultiColumns) {
//                            sb.append(String.format(errorMessageString + "的数据类型为存为多列的多值[业务字段]，暂不支持引用此类关联业务字段。"));
//                            sb.append("\n");
//                        }
//                    }
                }
            }
        }
        // 20191128-N版不支持此种场景，但去掉保存前校验
        //      if (element.IsUdt)
        //{
        //	string udtId = element.UdtID;
        //	var udtMeta= MetadataService.GetRefMetadata(udtId);
        //	if (udtMeta == null)
        //	{
        //		throw new Exception($"{FIELD}对应的udt元数据加载识别，udtId={udtId}。");
        //	}

        //	var udtContent = udtMeta.Content as UnifiedDataTypeDef;
        //	if (udtContent is SimpleDataTypeDef sUdt)
        //	{
        //		if (sUdt.ObjectType == GspElementObjectType.Association)
        //		{
        //			foreach (var refEle in sUdt.ChildAssociations[0].RefElementCollection)
        //			{
        //				if (refEle.ObjectType == GspElementObjectType.Association&&!refEle.IsUdt)
        //				{
        //					sb.append(String.format(FIELD + "的数据类型为关联类型的[业务字段]，且关联带出字段{3}为普通关联类型，暂不支持引用此类关联业务字段。", modelName, objName, element.Name,
        //						refEle.LabelID);
        //					sb.AppendLine();
        //				}
        //			}
        //		}
        //	}
        //}
    }

    //标签唯一性校验
    private String validateBizTags(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();
        for (IGspCommonObject aObject : aObjectList) {
            List<List<String>> tagLists = aObject.getContainElements().stream().filter(item->item.getBizTagIds() !=null && item.getBizTagIds().size() >0)
                    .map(a->a.getBizTagIds()).collect(Collectors.toList());
            List<String> tempList = new ArrayList<>();
            if(tagLists != null && tagLists.size() >0){
                for(List<String> tag:tagLists){
                    tempList.addAll(tag);
                }
                Map<String, Long> map = tempList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
                for(Map.Entry<String, Long> entry:map.entrySet()){
                    if(entry.getValue() > 1){
                        BizTagService bizTagService = SpringBeanUtils.getBean(BizTagService.class);
                        BizTag bizTag = bizTagService.getBizTagById(entry.getKey());
                        if(bizTag.isUnique())
                            return bizTag.getName() + "是唯一性标签，不允许被设置多次";
                    }
                }
            }
        }
        return sb.toString();
    }

    //字段
    private String validateElementBasicInfo(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();
        for (IGspCommonObject aObject : aObjectList) {
            java.util.ArrayList<IGspCommonElement> allElementList = aObject.getAllElementList(false);
            for (IGspCommonElement element : allElementList) {
                validateElementBasicInfo(element, sb, model.getName(), aObject.getName(), aObject.getCode(), model.getIsVirtual(), FIELD);
            }
        }
        return sb.toString();
    }

    /**
     * 是否符合命名规范
     * 字母数字下划线组成,字母下划线开头
     *
     * @param text
     * @return
     */
    private boolean ConformToNaminGspecification(String text) {
        String regex = "^[A-Za-z_][A-Za-z_0-9]*$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        boolean ismatch = matcher.matches();
        return ismatch;
    }

    //TODO：不校验字段的数据类型转换
    private String validateElementDataType(GspBusinessEntity model) {
        return "";
        //  StringBuilder sb = new StringBuilder();
        //  List<IGspCommonObject> aObjectList = model.GetAllObjectList();
        //  foreach (IGspCommonObject aObject in aObjectList)
        //  {
        //   string tableName = aObject.RefObjectName;
        //   DatabaseObjectTable dtab = ServiceManager.GetService<IDatabaseObjectService>()
        //    .GetDatabaseObject(tableName, DatabaseObjectType.Table) as DatabaseObjectTable;

        //List<IGspCommonElement> elementList = aObject.GetAllElementList(false);
        //   foreach (IGspCommonElement ele in elementList)
        //   {
        //    GspElementDataType type = ele.MDataType;
        //    string baseType = string.Empty;

        //    if (dtab != null && dtab.Columns.Count > 0)
        //    {
        //	    foreach (DatabaseObjectColumn column in dtab.Columns)
        //	    {
        //		    if (ele.ColumnID == column.ID)
        //		    {
        //			    if (!this.CompareDataType(ele, column))
        //			    {
        //				    sb.append(String.format(FIELD + "的 [数据类型] 与数据对象中数据类型不能做匹配转换! ", model.Name, aObject.Name, ele.Name);
        //				    sb.AppendLine();
        //			    }
        //			    break;
        //		    }
        //	    }
        //    }
        //   }
        //  }
        //  return sb.ToString();
    }

    private boolean CompareDataType(IGspCommonElement element, DatabaseObjectColumn column) {
        //TODO: 若已经生成了dbo，需要检查字段类型修改的兼容性
        boolean isRight = true;
        return isRight;
    }

    /**
     * [字段] 校验业务字段相关属性
     *
     * @param model
     * @return
     */

    private String validateElementUdt(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();
        for (IGspCommonObject aObject : aObjectList) {
            java.util.ArrayList<IGspCommonElement> allElementList = aObject.getAllElementList(false);
            for (IGspCommonElement element : allElementList) {
                GspBizEntityElement bizElement = (GspBizEntityElement) element;
                if (bizElement.getIsUdt() && CheckInfoUtil.checkNull(bizElement.getUdtID())) {
                    sb.append(String.format(FIELD + "的数据类型为[业务字段]，请配置其对应的业务字段。", model.getName(), aObject.getName(), element.getName()));
                    sb.append("\n");
                } else if (bizElement.getIsUdt()) {
                    String result = ValudateElementUdt(model, aObject, bizElement);
                    if (result.length() > 0) {
                        sb.append(result).append("\r\n");
                    }
                }
            }
        }
        return sb.toString();
    }

    private String ValudateElementUdt(GspBusinessEntity model, IGspCommonObject aObject, GspBizEntityElement bizElement) {
        if (bizElement.getObjectType() != GspElementObjectType.Association) {
            return "";
        }


        GspMetadata udtMetadata = getMetadataService().getRefMetadata(bizElement.getUdtID());
        if (udtMetadata == null) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0024, bizElement.getLabelID(), bizElement.getUdtID());
        }
        SimpleDataTypeDef udt = (SimpleDataTypeDef) ((udtMetadata.getContent() instanceof SimpleDataTypeDef) ? udtMetadata.getContent() : null);
        if (!udt.getCode().equals(bizElement.getLabelID())) {
            return "";
        }


        for (IGspCommonField refElement : bizElement.getChildAssociations().get(0).getRefElementCollection()) {
            if (!refElement.getIsFromAssoUdt()) {
                return String.format(FIELD + "的字段标签与所选UDT元数据编号相同时，不允许在be上添加带出字段。", model.getName(), aObject.getName(), bizElement.getName());
            }
        }

        return "";
    }

    ///#endregion


    ///#region Operation

    /**
     * [操作]联动计算
     *
     * @param model
     * @return
     */
    private String validateDeterminations(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
//C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
        ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();//.stream().collect(item ->item instanceof GspBizEntityObject)
        for (IGspCommonObject aObject : aObjectList) {
            CommonDtmCollection collection = ((GspBizEntityObject) aObject).getBizCommonDtms();
            List<CommonOperation> actions = collection.stream().collect(Collectors.toList());

            String errorMessage = String.format(OPT_DETERMINATION, model.getName(), aObject.getName());
            //①必填项
            sb.append(String.format(validateCommonOperationBasicInfo(errorMessage, (ArrayList<CommonOperation>) actions)));
            if (sb.length() > 0) {
                return sb.toString();
            }
            //②编号重复
            sb.append(String.format(validateCommonOperationCodeRepeat(errorMessage, (ArrayList<CommonOperation>) actions)));

            //③校验数据状态
//            sb.append(String.format(validateDeterminationSelfProperty(errorMessage, actions)));

            sb.append(String.format(validateDeterminationRequestElements(aObject, errorMessage, (ArrayList<CommonOperation>) actions)));
        }
        return sb.toString();
    }

    /**
     * [操作]校验规则
     *
     * @param model
     * @return
     */
    private String validateValidations(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
//C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
        java.util.ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();//.stream().m.parallelStream()..ConvertAll(item => (GspBizEntityObject)item);
        for (IGspCommonObject aObject : aObjectList) {
//            java.util.ArrayList<BizOperation> actions = ((GspBizEntityObject) aObject).getValidations();

            CommonValCollection collection = ((GspBizEntityObject) aObject).getBizCommonVals();
            List<CommonOperation> actions = collection.stream().collect(Collectors.toList());
            String errorMessage = String.format(OPT_VALIDATION, model.getName(), aObject.getName());
            //①必填项
            sb.append(String.format(validateCommonOperationBasicInfo(errorMessage, (ArrayList<CommonOperation>) actions)));
            if (sb.length() > 0) {
                return sb.toString();
            }
            //②编号重复
            sb.append(String.format(validateCommonOperationCodeRepeat(errorMessage, (ArrayList<CommonOperation>) actions)));
            //③触发时机至少选一个
//            sb.append(String.format(validateValidationSelfProperty(errorMessage, actions)));
            sb.append(String.format(validateValidationRequestElements(aObject, errorMessage, (ArrayList<CommonOperation>) actions)));
        }
        return sb.toString();
    }

    /**
     * 联动计算至少选择一个数据状态
     *
     * @param errorMessage
     * @param operations
     * @return
     */
    private String validateDeterminationSelfProperty(String errorMessage, java.util.ArrayList<BizOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size(); i++) {
                if (operations.get(i) instanceof Determination) {
                    Determination dtm = (Determination) operations.get(i);
                    if (dtm.getTriggerTimePointType().equals(EnumSet.of(BETriggerTimePointType.AfterModify)) || dtm.getTriggerTimePointType().equals(EnumSet.of(BETriggerTimePointType.BeforeCheck))) {
                        if (dtm.getRequestNodeTriggerType().equals(EnumSet.of(RequestNodeTriggerType.None))) {
                            String message = String.format(errorMessage + dtm.getName() + "的 [数据状态] (创建、更新、删除)至少选择一种。");
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                } else {
                    throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0025, errorMessage, operations.get(i).getName(), "Validation");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 校验触发字段是否存在
     * @param errorMessage
     * @param operations
     * @return
     */
    private String validateDeterminationRequestElements(IGspCommonObject gspCommonObject, String errorMessage, java.util.ArrayList<CommonOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size(); i++) {
                if (!(operations.get(i) instanceof BizCommonDetermination)) {
                    throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0025, errorMessage, operations.get(i).getName(), "Determination");
                }
                BizCommonDetermination dtm = (BizCommonDetermination) operations.get(i);
                com.inspur.edp.cef.designtime.api.collection.DtmElementCollection dtmElementCollection = dtm.getRequestElements();
                if(dtmElementCollection != null && dtmElementCollection.size() > 0){
                    for(String element: dtmElementCollection){
                        if(gspCommonObject.findElement(element) == null){
                            String message = errorMessage + dtm.getName() + "的 [触发字段]" + element + "在节点中不存在!";
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                }
                HashMap<String, DtmElementCollection> childDtmElements = dtm.getRequestChildElements();
                if(childDtmElements == null || childDtmElements.size() == 0)
                    continue;
                for(Map.Entry<String, DtmElementCollection> entry: childDtmElements.entrySet()){
                    String key = entry.getKey();
                    DtmElementCollection value = entry.getValue();
                    IObjectCollection childObjects = gspCommonObject.getContainChildObjects();
                    if(childObjects == null || childObjects.size() ==0){
                        String message = errorMessage + dtm.getName() + "的 触发字段对应子节点" + key + "在在节点中不存在!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    IGspCommonObject reqChildObj = null;
                    for(IGspCommonObject childObj : childObjects){
                        if(childObj.getID().equals(key)){
                            reqChildObj = childObj;
                            break;
                        }
                    }
                    if(reqChildObj == null){
                        String message = errorMessage + dtm.getName() + "的 触发字段对应子节点" + key + "在子节点中不存在!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    if(value == null || value.getCount() == 0){
                        String message = errorMessage + dtm.getName() + "的 触发字段对应子节点" + key + "未设置触发字段!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    for(String childElement: value){
                        if(reqChildObj.findElement(childElement) == null){
                            String message = errorMessage + dtm.getName() + "的 触发字段" + childElement + "在字段列表中不存在!";
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                }
            }
        }
        return sb.toString();
    }

    private String validateValidationRequestElements(IGspCommonObject gspCommonObject, String errorMessage, java.util.ArrayList<CommonOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size(); i++) {
                if (!(operations.get(i) instanceof CommonValidation)) {
                    throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0025, errorMessage, operations.get(i).getName(), "Validation");
                }
                BizCommonValdation val = (BizCommonValdation) operations.get(i);
                ValElementCollection valElementCollection = val.getRequestElements();
                if(valElementCollection != null && valElementCollection.size() > 0){
                    for(String element: valElementCollection){
                        if(gspCommonObject.findElement(element) == null){
                            String message = errorMessage + val.getName() + "的 [触发字段]" + element + "在节点中不存在!";
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                }
                HashMap<String, ValElementCollection> childValElements = val.getRequestChildElements();
                if(childValElements == null || childValElements.size() == 0)
                    continue;
                for(Map.Entry<String, ValElementCollection> entry: childValElements.entrySet()){
                    String key = entry.getKey();
                    ValElementCollection value = entry.getValue();
                    IObjectCollection childObjects = gspCommonObject.getContainChildObjects();
                    if(childObjects == null || childObjects.size() ==0){
                        String message = errorMessage + val.getName() + "的 触发字段对应子节点" + key + "在在节点中不存在!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    IGspCommonObject reqChildObj = null;
                    for(IGspCommonObject childObj : childObjects){
                        if(childObj.getID().equals(key)){
                            reqChildObj = childObj;
                            break;
                        }
                    }
                    if(reqChildObj == null){
                        String message = errorMessage + val.getName() + "的 触发字段对应子节点" + key + "在子节点中不存在!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    if(value == null || value.getCount() == 0){
                        String message = errorMessage + val.getName() + "的 触发字段对应子节点" + key + "未设置触发字段!";
                        sb.append(message);
                        sb.append("\n");
                        continue;
                    }
                    for(String childElement: value){
                        if(reqChildObj.findElement(childElement) == null){
                            String message = errorMessage + val.getName() + "的 触发字段" + childElement + "在字段列表中不存在!";
                            sb.append(message);
                            sb.append("\n");
                        }
                    }
                }
            }
        }
        return sb.toString();
    }
    /**
     * 校验规则至少选择一个执行时机/一个数据状态
     *
     * @param errorMessage
     * @param operations
     * @return
     */
    private String validateValidationSelfProperty(String errorMessage, java.util.ArrayList<BizOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size(); i++) {
                if (operations.get(i) instanceof Validation) {
                    Validation val = (Validation) operations.get(i);
                    if (val.getValidationTriggerPoints() == null || val.getValidationTriggerPoints().size() == 0) {
                        String message = String.format(errorMessage + val.getName() + "的 [执行时机] 至少选择一种。");
                        sb.append(message);
                        sb.append("\n");
                    } else {
                        boolean hasTimePoint = false;

                        for (Map.Entry<BETriggerTimePointType, EnumSet<RequestNodeTriggerType>> point : val.getValidationTriggerPoints().entrySet()) {
                            if (!(point.getValue().equals(EnumSet.of(RequestNodeTriggerType.None)))) {
                                hasTimePoint = true;
                            }
                        }
                        if (!hasTimePoint) {
                            String message = String.format(errorMessage + val.getName() + "的 [执行时机] 至少选择一种。");
                            sb.append(message);
                            sb.append("\n");
                        }
                    }

                    //if (val.TriggerTimePointType ==BETriggerTimePointType.None)
                    //{
                    //	string message = string.Format(errorMessage + $"'{val.Name}'的 [执行时机] 至少选择一种。");
                    //	sb.Append(message);
                    //	sb.AppendLine();
                    //}

                    //if (val.RequestNodeTriggerType ==RequestNodeTriggerType.None)
                    //{
                    //	string message = string.Format(errorMessage + $"'{val.Name}'的 [数据状态] 至少选择一种。");
                    //	sb.Append(message);
                    //	sb.AppendLine();
                    //}
                } else {
                    throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0025, errorMessage, operations.get(i).getName(), "Validation");
                }
            }
        }
        return sb.toString();
    }

    /**
     * [操作]业务实体动作
     *
     * @param model
     * @return
     */
    private String validateBeActions(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
//C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
        ArrayList<IGspCommonObject> aObjectList = model.getAllObjectList();//.ConvertAll(item => (GspBizEntityObject)item);
        for (IGspCommonObject aObject : aObjectList) {
            java.util.ArrayList<BizOperation> actions = ((GspBizEntityObject) aObject).getBizActions();

            String errorMessage = String.format(OPT_BIZACTION, model.getName(), aObject.getName());
            //①必填项
            sb.append(String.format(validateOperationBasicInfo(errorMessage, actions)));
            if (sb.length() > 0) {
                return sb.toString();
            }
            //②编号重复
            sb.append(String.format(validateOperationCodeRepeat(errorMessage, actions)));
            if (sb.length() > 0) {
                return sb.toString();
            }
            //③参数及返回值校验
            sb.append(String.format(validateActionParas(errorMessage, actions)));
        }
        return sb.toString();
    }

    /**
     * [操作]自定义动作
     *
     * @param model
     * @return
     */
    private String validateMgrActions(GspBusinessEntity model) {
        String errorMessage = String.format(OPT_MGRACTION, model.getName());
        StringBuilder sb = new StringBuilder();
        java.util.ArrayList<BizOperation> actions = model.getBizMgrActions();
        //①必填项
        sb.append(String.format(validateOperationBasicInfo(errorMessage, actions)));
        if (sb.length() > 0) {
            return sb.toString();
        }
        //②编号重复
        sb.append(String.format(validateOperationCodeRepeat(errorMessage, actions)));
        if (sb.length() > 0) {
            return sb.toString();
        }
        //③参数及返回值校验
        sb.append(String.format(validateActionParas(errorMessage, actions)));
        return sb.toString();
    }

    /**
     * [操作]编号重复
     *
     * @param errorMessage
     * @param operations
     * @return
     */
    private String validateOperationCodeRepeat(String errorMessage, java.util.ArrayList<BizOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size() - 1; i++) {
                BizOperation firstOperation = operations.get(i);
                for (int j = i + 1; j < operations.size(); j++) {
                    BizOperation secondOperation = operations.get(j);
                    if (firstOperation.getCode().equals(secondOperation.getCode())) {
                        String message = String.format(errorMessage + "'{%1$s}'与'{%2$s}'的编号重复，重复编号为：【"+firstOperation.getCode()+"】", firstOperation.getName(), secondOperation.getName());
                        sb.append("\n");
                        return message;
                    }
                }
            }
        }
        return sb.toString();
    }

    /**
     * [操作]编号名称为空
     *
     * @param errorMessage
     * @param oprs
     * @return
     */
    private String validateOperationBasicInfo(String errorMessage, java.util.ArrayList<BizOperation> oprs) {
        if (oprs == null || oprs.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();

        for (BizOperation opr : oprs) {
            if (CheckInfoUtil.checkNull(opr.getID())) {
                opr.setID(UUID.randomUUID().toString());
                //sb.append(String.format(errorMessage + string.Format("'{0}'的 [ID] 属性不允许为空! ", opr.Name));
                //sb.AppendLine();
            }
            if (CheckInfoUtil.checkNull(opr.getCode())) {
                sb.append(String.format(errorMessage + String.format("'%1$s'的 [编号] 属性不允许为空! ", opr.getName())));
                sb.append("\n");
            } else {
                // 操作Code限制非法字符
                if (!ConformToNaminGspecification(opr.getCode())) {
                    sb.append(String.format(errorMessage + String.format("'%1$s'的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", opr.getName())));
                    sb.append("\n");
                }
            }
            if (CheckInfoUtil.checkNull(opr.getName())) {
                sb.append(String.format(errorMessage + String.format("'%1$s'的 [名称] 属性不允许为空! ", opr.getCode())));
                sb.append("\n");
            }
        }
        return sb.toString();
    }


    /**
     * [操作]编号重复
     *
     * @param errorMessage
     * @param operations
     * @return
     */
    private String validateCommonOperationCodeRepeat(String errorMessage, java.util.ArrayList<CommonOperation> operations) {
        StringBuilder sb = new StringBuilder();
        if (operations != null && operations.size() > 0) {
            for (int i = 0; i < operations.size() - 1; i++) {

                CommonOperation firstOperation = operations.get(i);
                for (int j = i + 1; j < operations.size(); j++) {

                    CommonOperation secondOperation = operations.get(j);
                    if (firstOperation.getCode().equals(secondOperation.getCode())) {
                        String message = String.format(errorMessage + "%1$s与%2$s的编号重复，重复编号为：【"+firstOperation.getCode()+"】", firstOperation.getName(), secondOperation.getName());
                        sb.append("\n");
                        return message;
                    }
                }
            }
        }
        return sb.toString();
    }

    /**
     * [操作]编号名称为空
     *
     * @param errorMessage
     * @param oprs
     * @return
     */
    private String validateCommonOperationBasicInfo(String errorMessage, java.util.ArrayList<CommonOperation> oprs) {
        if (oprs == null || oprs.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();

        for (CommonOperation opr : oprs) {
            if (CheckInfoUtil.checkNull(opr.getID())) {
                opr.setID(UUID.randomUUID().toString());
                //sb.append(String.format(errorMessage + string.Format("'{0}'的 [ID] 属性不允许为空! ", opr.Name));
                //sb.AppendLine();
            }
            if (CheckInfoUtil.checkNull(opr.getCode())) {
                sb.append(String.format(errorMessage + String.format("'%1$s'的 [编号] 属性不允许为空! ", opr.getName())));
                sb.append("\n");
            } else {
                // 操作Code限制非法字符
                if (!ConformToNaminGspecification(opr.getCode())) {
                    sb.append(String.format(errorMessage + String.format("'%1$s'的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", opr.getName())));
                    sb.append("\n");
                }
            }
            if (CheckInfoUtil.checkNull(opr.getName())) {
                sb.append(String.format(errorMessage + String.format("'%1$s'的 [名称] 属性不允许为空! ", opr.getCode())));
                sb.append("\n");
            }
        }
        return sb.toString();
    }

    /**
     * [操作]-action-参数
     *
     * @param opr
     * @param errorMessage
     * @return
     */
    private String validateActionReturnValue(BizActionBase opr, String errorMessage) {
        StringBuilder sb = new StringBuilder();
        BizReturnValue returnValue = opr.getReturnValue();
        if (returnValue != null && returnValue.getParameterType() == BizParameterType.Custom) {
            if (BeManagerService.CreatJavaModule(metaPath)) {
                if (opr.getIsGenerateComponent() && CheckInfoUtil.checkNull(returnValue.getClassName())) {
                    sb.append(String.format("J版元数据工程，" + errorMessage + "'%1$s'中的返回值的 [类型] 为自定义类型，请完善其Java类名。", opr.getName()));
                    sb.append("\n");
                }
            }
        }
        return sb.toString();
    }


    /**
     * 校验动作参数及返回值
     *
     * @param errorMessage
     * @param actions
     * @return
     */
    private String validateActionParas(String errorMessage, java.util.ArrayList<BizOperation> actions) {
        StringBuilder sb = new StringBuilder();
        if (actions != null && actions.size() > 0) {

            for (BizOperation action : actions) {
                sb.append(String.format(validateActionParas((BizActionBase) action, errorMessage)));
                sb.append(String.format(validateActionComponent((BizActionBase) action, errorMessage)));
                sb.append(String.format(validateActionReturnValue((BizActionBase) action, errorMessage)));
            }
        }
        return sb.toString();
    }

    private String validateActionParas(BizActionBase opr, String message) {
        StringBuilder sb = new StringBuilder();
        //参数编号名称不可为空

        for (Object para : opr.getParameters()) {
            if (CheckInfoUtil.checkNull(((IBizParameter) para).getParamCode())) {
                sb.append(String.format(message + String.format("'%1$s'中的参数'%2$s'的 [编号] 属性不允许为空! ", opr.getName(), ((IBizParameter) para).getParamName())));
                sb.append("\n");
            } else {
                // 参数编号Code限制非法字符
                if (!ConformToNaminGspecification(((IBizParameter) para).getParamCode())) {
                    sb.append(String.format(message + String.format("'%1$s'中的参数'%2$s'的 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", opr.getName(), ((IBizParameter) para).getParamName())));
                    sb.append("\n");
                }
            }
            if (CheckInfoUtil.checkNull(((IBizParameter) para).getParamName())) {
                sb.append(String.format(message + String.format("'%1$s'中的参数'%2$s'的 [名称] 属性不允许为空! ", opr.getCode(), ((IBizParameter) para).getParamCode())));
                sb.append("\n");
            }
            if (((IBizParameter) para).getParameterType() == BizParameterType.Custom) {
                if (BeManagerService.CreatJavaModule(metaPath)) {
                    if (opr.getIsGenerateComponent() && CheckInfoUtil.checkNull(((IBizParameter) para).getClassName())) {
                        sb.append(String.format("J版元数据工程，" + message + "'%1$s'中的参数'%2$s' [参数类型] 为自定义类型，请完善其Java类名。", opr.getName(), ((IBizParameter) para).getParamName()));
                        sb.append("\n");
                    }
                }
            }
        }
        if (sb.length() > 0) {
            return sb.toString();
        }

        //参数编号不可重复
        if (opr.getParameters() != null && opr.getParameters().getCount() > 0) {
            for (int i = 0; i < opr.getParameters().getCount() - 1; i++) {
                IBizParameter firstPara = opr.getParameters().getItem(i);
                for (int j = i + 1; j < opr.getParameters().getCount(); j++) {
                    IBizParameter secondPara = opr.getParameters().getItem(j);
                    if (firstPara.getParamCode().equals(secondPara.getParamCode())) {
                        sb.append(String.format(message + "'{%1$s}'中的参数'{%2$s}'和参数'{%3$s}'的[编号] 属性不允许重复,重复编号为：【"+firstPara.getParamCode()+"】", opr.getName(), firstPara.getParamName(), secondPara.getParamName()));
                        sb.append("\n");
                    }
                }
            }
        }
        return sb.toString();
    }


    private String validateActionComponent(BizActionBase opr, String message) {
        //内置实体动作和自定义动作不用校验
        if(opr instanceof IInternalMgrAction || opr instanceof IInternalBEAction)
            return "";
        StringBuilder sb = new StringBuilder();
        //参数编号名称不可为空
        ICompParameterCollection compParameterCollection = null;
        if(!opr.getIsGenerateComponent() && StringUtils.isEmpty(opr.getComponentId())){
            sb.append(String.format(message + String.format("'%1$s'中构件ID 属性不允许为空! ", opr.getName())));
            sb.append("\n");
            return sb.toString();
        }
        //新增的时候，构件ID是空的
        if(StringUtils.isEmpty(opr.getComponentId())){
            return sb.toString();
        }
        RefCommonService metadataService = SpringBeanUtils.getBean(RefCommonService.class);
        GspMetadata metadata = metadataService.getRefMetadata(opr.getComponentId());
        if(metadata == null){
            sb.append(String.format(message + String.format("'%1$s'对应的构件元数据不存在!", opr.getName())));
            sb.append("\n");
            return sb.toString();
        }
        if(metadata.getContent() instanceof GspComponent) {
            if(!opr.getIsGenerateComponent()){
                GspComponent component = (GspComponent) metadata.getContent();
                compParameterCollection = component.getMethod().getCompParameterCollection();
                int oprParSize = opr.getParameters() == null ? 0 : opr.getParameters().getCount();
                int compParSize = compParameterCollection == null ? 0 :compParameterCollection.getCount();
                if(oprParSize != compParSize){
                    sb.append(String.format(message + String.format("'%1$s'的参数个数为:%2$s,构件上参数个数:%3$s!", opr.getName(), oprParSize, compParSize)));
                    sb.append("\n");
                    return sb.toString();
                }
            }
        }
        if(!opr.getIsGenerateComponent()){
            for(int i=0; i< opr.getParameters().getCount(); i++){
                IBizParameter bizParameter = opr.getParameters().getItem(i);
                ICompParameter compParameter = compParameterCollection.getItem(i);
                //引用构件的才校验
                sb.append(validBizCompParameter(bizParameter, compParameter, opr, message));
            }
        }

        if (sb.length() > 0) {
            return sb.toString();
        }

        //参数编号不可重复
        if (opr.getParameters() != null && opr.getParameters().getCount() > 0) {
            for (int i = 0; i < opr.getParameters().getCount() - 1; i++) {
                IBizParameter firstPara = opr.getParameters().getItem(i);
                for (int j = i + 1; j < opr.getParameters().getCount(); j++) {
                    IBizParameter secondPara = opr.getParameters().getItem(j);
                    if (firstPara.getParamCode().equals(secondPara.getParamCode())) {
                        sb.append(String.format(message + "'{0}'中的参数'{1}'和参数'{2}'的[编号] 属性不允许重复,重复编号为：【"+firstPara.getParamCode()+"】", opr.getName(), firstPara.getParamName(), secondPara.getParamName()));
                        sb.append("\n");
                    }
                }
            }
        }
        return sb.toString();
    }

    private String validBizCompParameter( IBizParameter bizParameter, ICompParameter compParameter,  BizActionBase bizActionBase, String message){
        StringBuilder sb = new StringBuilder();
        if(!bizParameter.getParamCode().equalsIgnoreCase(compParameter.getParamCode())){
            sb.append(String.format(message + "'%1$s'中的参数'%2$s'和构件参数'%3$s'的[编号] 属性不一致", bizActionBase.getName(), bizParameter.getParamCode(), compParameter.getParamCode()));
        }
        //老的BE存在为空的情况
//        if(!bizParameter.getClassName().equalsIgnoreCase(compParameter.getClassName())){
//            sb.append(String.format(message + "'%1$s'中的参数'%2$s'和构件参数的[类型] 属性不一致，类型分别为'%3$s','%4$s'", bizActionBase.getName(), bizParameter.getParamCode(),bizParameter.getClassName(), compParameter.getClassName()));
//        }
        return sb.toString();
    }

    /**
     * [操作]业务实体动作
     *
     * @param model
     * * @return
     */
    private String validateTccSettingCollection(GspBusinessEntity model) {
        StringBuilder sb = new StringBuilder();
        ArrayList<IGspCommonObject> objectList = model.getAllObjectList();
        for(IGspCommonObject object: objectList){
            String errorMessage = String.format(TCCSETTINGS, model.getName(), object.getName());
            TccSettingCollection settings = ((GspBizEntityObject)object).getTccSettings();
            // ①TCC配置字段校验
            for(TccSettingElement ele: settings) {
                sb.append(validateTccElement(errorMessage, ele));
            }
            // ②TCC字段Code重复性校验
            String repeatMessage = validateTccSettingCollectionCodeRepeat(errorMessage,((GspBizEntityObject) object).getTccSettings());
            if (!StringUtils.isEmpty(repeatMessage)) {
                sb.append(validateTccSettingCollectionCodeRepeat(errorMessage,((GspBizEntityObject) object).getTccSettings()));
            }
        }
        return sb.toString();
    }

    private String validateTccElement(String errorMessage, TccSettingElement element) {
        StringBuilder sb = new StringBuilder();
        if (CheckInfoUtil.checkNull(element.getCode())) {
            sb.append(String.format(errorMessage + "的TCC配置字段的 [编号] 属性不允许为空! ",element.getName()));
            sb.append("\n");
        } else {
            // 字段Code限制非法字符
            if (!ConformToNaminGspecification(element.getCode())) {
                sb.append(String.format(errorMessage + "的TCC配置字段 [编号] 属性必须以英文字母或下划线开头, 并且只能由英文字母、数字、下划线(_)组成! ", element.getName()));
                sb.append("\n");
            }
            // 字段Code限制数据库保留字
            else if (isDatabaseReservedWords(element.getCode())) {
                sb.append(String.format(errorMessage + "的 [编号] '%3$s'为数据库保留字，请修改。 ", element.getName(), element.getCode()));
                sb.append("\n");
            }
            else if (isDatabaseObjectReservedWords(element.getCode())) {
                sb.append(String.format(errorMessage + "的 [编号] '%3$s'为数据库对象保留字（时间戳字段或租户字段TenantID），请修改。 ",  element.getName(), element.getCode()));
                sb.append("\n");
            }
        }
        if (CheckInfoUtil.checkNull(element.getName())) {
            sb.append(String.format(errorMessage + "的 [名称] 属性不允许为空! ", element.getCode()));
            sb.append("\n");
        }

        String validateTccAtionResult = validateTccAction(errorMessage,element);
        if(!CheckInfoUtil.checkNull(validateTccAtionResult)) {
            sb.append(validateTccAtionResult);
        }
        return sb.toString();
    }

    private String validateTccAction(String errorMessage, TccSettingElement element) {
        ArrayList<BizOperation> actions = new ArrayList<>();
        actions.add(element.getTccAction());
        return validateOperationBasicInfo(errorMessage,actions);
    }

    private String validateTccSettingCollectionCodeRepeat(String errorMessage, TccSettingCollection collection) {
        if(collection != null && collection.size() > 0) {
            for (int i =0; i< collection.size() -1; i++) {
                TccSettingElement firstEle = collection.get(i);
                for(int j = i+1; j<collection.size(); j++) {
                    TccSettingElement secondEle = collection.get(j);
                    if (firstEle.getCode().equals(secondEle.getCode())) {
                        String message = String.format(errorMessage + "%1$s与%2$s的编号重复，重复编号为：【"+firstEle.getCode()+"】", firstEle.getName(), secondEle.getName());
                        return message;
                    }
                }
            }
        }
        return null;
    }
    ///#endregion


    ///#region Util

    private boolean isDatabaseReservedWords(String word) {
        return DatabaseReservedWords.isReservedWord(word);
    }

    /*
    是否Farrias前端关键字
     */
    private boolean isFarriasReservedWords(String word){
        if(word == null || word.length() == 0)
            return false;
        if(farriasKeyWrods.contains(word.toLowerCase())){
            return true;
        }
        return false;
    }

    private ReserveResult getReservedResult(String words, String errorMessage, String modelName, String objName, String propName, IGspCommonField element){
        ReserveResult reserveResult = new ReserveResult();
        if(isDatabaseReservedWords(words)){
            reserveResult.isKeyWords = true;
            reserveResult.message = String.format(errorMessage + "的 [%4$s] '%5$s'为数据库保留字，请修改。 ", modelName, objName, element.getName(), propName, element.getCode());
            return reserveResult;
        }
        if(isFarriasReservedWords(words)){
            reserveResult.isKeyWords = true;
            reserveResult.message = String.format(errorMessage + "的 [%4$s] '%5$s'为前端保留字，请修改。 ", modelName, objName, element.getName(), propName, element.getCode());
            return reserveResult;
        }
        return reserveResult;
    }

    private boolean isDatabaseObjectReservedWords(String word) {
        //todo:[启用时间戳]方案成熟前，先隐藏
        //return DatabaseObjectReservedWords.IsReservedWord(word);
        return false;
    }

    private static java.util.ArrayList<String> fwkReserveds = new java.util.ArrayList<String>(java.util.Arrays.asList(new String[]{"DynamicPropSet"}));

    private static boolean isFrameworkReservedWords(String word) {
        return fwkReserveds.contains(word);
    }

    class ReserveResult{
        private boolean isKeyWords = false;
        private String message = "";
    }
    ///#endregion
}
